#include "ExeVisitor.h"

ExeVisitor::ExeVisitor() 
{
    exe_state* var_exe= new exe_state;
};

ExeVisitor::~ExeVisitor()
{   
    //delete  var_exe;
};

antlrcpp::Any ExeVisitor::visitQuerySpecification(MySqlParser::QuerySpecificationContext *ctx)
{   
    // TEST PART

    // 1. select part
    // the simple version
    /*
    select_ds* var_s = ctx->selectElements()->accept(this).as<select_ds*>();
    var_s ->  test();
    */

    // the complex version
    /*std::vector<select_ds*> var_s = ctx->selectElements()->accept(this).as<std::vector<select_ds*>>();
    for(int i=0 ; i<var_s.size() ; i++) {
        var_s[i] -> test();
    }
    return NULL;*/

    // 2. join part
    //the simple version
    
    // from_ds* var_f  = ctx->fromClause()->accept(this).as<from_ds*>();
    // var_f -> test();
    // return NULL;
    

    // 3. group part
    /* simple verison
    group_ds* var_g = ctx->groupByClause()->accept(this).as<group_ds*>();
    var_g->test(); 
    */
    // complex version
    /*std::vector<group_ds*> var_g = ctx->groupByClause()->accept(this).as<std::vector<group_ds*>>();
    for(int i=0 ; i<var_g.size() ; i++) {
        var_g[i] -> test();
    }
    return NULL;*/

    // DECIDE PHASE
    std::vector<select_ds*> var_s = ctx->selectElements()->accept(this).as<std::vector<select_ds*>>();
    from_ds* var_f  = ctx->fromClause()->accept(this).as<from_ds*>();
    std::vector<group_ds*> var_g = ctx->groupByClause()->accept(this).as<std::vector<group_ds*>>();
    for(int i=0 ; i<var_s.size() ; i++) {
        var_exe -> decide(var_s[i], var_f, var_g);
    }
    return NULL;
}




// 1. select part 
antlrcpp::Any ExeVisitor::visitSelectElements(MySqlParser::SelectElementsContext *ctx)
{
    // consider the most simple condition
    // select_ds* var_s = new select_ds;
    // antlrcpp::Any va = ctx->selectElement(0)->accept(this);
    // if( va.is<select_ds*>() )
    //     var_s = va.as<select_ds*>();
    // else {
    //     var_s->change_f(0);
    //     var_s->change_t(*(va.as<ta*>()));
    // }

    // consider the complex version
    std::vector<MySqlParser::SelectElementContext*> va = ctx->selectElement();
    std::vector<select_ds*> var_s;
    for(int i=0; i<va.size(); i++){
        antlrcpp::Any val = va[i]->accept(this);
        if( val.is<select_ds*>() )
            var_s.push_back(val.as<select_ds*>());
        else {
            select_ds* tmp = new select_ds;
            tmp->change_f(0);
            tmp->change_t(*(val.as<ta*>()));
            var_s.push_back(tmp);
        }
    }
    return var_s;
}

antlrcpp::Any ExeVisitor::visitAggregateWindowedFunction(MySqlParser::AggregateWindowedFunctionContext *ctx){
    /* one way
    std::string s = ctx->getText().substr(0,3);
        modify agg type
        if(s == "SUM") var_s->change_f(1);
        else if(s == "AVG") var_s->change_f(2);
        else var_s->change_f(3);
    */
    select_ds* var_s = new select_ds;

    if( ctx->SUM() != NULL) 
        var_s->change_f(1);
    else if ( ctx->AVG() != NULL)
        var_s->change_f(2);
    else if ( ctx->COUNT() != NULL)
        var_s->change_f(3);

    // trans value
    var_s->change_t(*(ctx->functionArg()->accept(this).as<ta*>()));

    return var_s;
}

antlrcpp::Any ExeVisitor::visitAggregateFunctionCall(MySqlParser::AggregateFunctionCallContext *ctx){
    // std::string s = ctx->getText();
    // std::cout << "agg_fun:" + s << std::endl;
    return visitChildren(ctx);
}




// 2. from join part
antlrcpp::Any ExeVisitor::visitFromClause(MySqlParser::FromClauseContext *ctx) {
    return ctx->tableSources()->tableSource(0)->accept(this);
}

antlrcpp::Any ExeVisitor::visitTableSourceBase(MySqlParser::TableSourceBaseContext *ctx) {
    // simple version
    from_ds* var_f = new from_ds;
    if( ctx->joinPart(0) != NULL ){
        return ctx->joinPart(0)->accept(this);
    }
    else {
        var_f -> flag = 0 ;
        // nonexsit join , no consider
    }
    return var_f;
}

antlrcpp::Any ExeVisitor::visitInnerJoin(MySqlParser::InnerJoinContext *ctx){
    return ctx->expression()->accept(this);
}

antlrcpp::Any ExeVisitor::visitBinaryComparisonPredicate(MySqlParser::BinaryComparisonPredicateContext *ctx) {
    from_ds* var_f = new from_ds;

    ta* one = ctx -> predicate(0) -> accept(this).as<ta*>() ;
    ta* two = ctx -> predicate(1) -> accept(this).as<ta*>() ;

    var_f -> change_t (*one , *two);
    var_f -> change_f (var_f->eq()) ;

    return var_f;
}




// 3. group by part
//
antlrcpp::Any ExeVisitor::visitGroupByClause(MySqlParser::GroupByClauseContext *ctx){
    // groupbyitem branch
    // std::vector<antlrcpptest::MySqlParser::GroupByItemContext*>::iterator itr = ctx->groupByItem().begin();
    // for(; itr != ctx->groupByItem().end(); ++itr)
    // {//std::cout << (*itr)  << std::endl;
    //     antlrcpp::Any value = (*itr)->accept(this);
    //     var_g->change_t(value.as<ta>());
    // }

    // simple version
    /*
    group_ds* var_g = new group_ds;
    if( ctx->GROUP() != NULL && ctx->BY() != NULL )
        var_g->change_s(1);
    ta* value = ctx->groupByItem(0)->accept(this).as<ta*>();
    var_g->change_t(*value);
    */

    // the complex version
    group_ds* tmp = new group_ds;
    // consider the special but should not exist condition
    if( ctx->GROUP() != NULL && ctx->BY() != NULL ) 
        tmp->change_f(1);
    std::vector<group_ds*> var_g;
    std::vector<MySqlParser::GroupByItemContext*> va = ctx->groupByItem();
    for(int i = 0; i < va.size(); i++){
        tmp -> change_t(*(va[i]->accept(this).as<ta*>()));
        var_g.push_back(tmp);
    }
    return var_g;
}

//    
antlrcpp::Any ExeVisitor::visitSimpleId(MySqlParser::SimpleIdContext *ctx){
    std::string s = ctx->getText();
    std::cout << "simpleid: " + s << std::endl;
    return visitChildren(ctx);
}

// unused 
antlrcpp::Any ExeVisitor::visitDottedId(MySqlParser::DottedIdContext *ctx){
    std::string s = ctx->getText();
    // std::cout << "dotted: " + s << std::endl;
    return visitChildren(ctx);
}

antlrcpp::Any ExeVisitor::visitFullColumnName(MySqlParser::FullColumnNameContext *ctx){
    ta* var = new ta;
    // get uid branch
    var->name = ctx->uid()->simpleId()->getText();
    // get dottedid
    var->column = ctx->dottedId(0)->getText();
    return antlrcpp::Any(var);
} 